﻿#region Imports
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using BookManager.Models;
using BookManager.Views;
using CommonUtilities.Commands;
using CommonUtilities.Enums;
using CommonUtilities.Extensions;
using CommonUtilities.Util;
#endregion Imports

namespace BookManager.ViewModels
{
    public class MainViewModel : BaseViewModel
    {
        string dbp = @"C:\Users\rhythm divine\Documents\Visual Studio 2010\Projects\BookManager\BookManager\Database";

        #region Properties
        private bool displayDetails;
        public bool DisplayDetails
        {
            get { return displayDetails; }
            set { displayDetails = value; RaisePropertyChanged("DisplayDetails"); }
        }

        private ObservableCollection<Book> allBooks = new ObservableCollection<Book>();
        public ObservableCollection<Book> AllBooks
        {
            get { return allBooks; }
            set { allBooks = value; RaisePropertyChanged("AllBooks"); }
        }

        private ObservableCollection<Book> allBooks_org;
        public ObservableCollection<Book> AllBooks_org
        {
            get { return allBooks_org; }
            set { allBooks_org = value; }
        }

        private ObservableCollection<Book> allFilteredBooks = new ObservableCollection<Book>();
        public ObservableCollection<Book> AllFilteredBooks
        {
            get { return allFilteredBooks; }
            set
            {
                allFilteredBooks = value; RaisePropertyChanged("AllFilteredBooks");
                HasResults = allFilteredBooks.Any();
            }
        }

        private bool hasResults;
        public bool HasResults
        {
            get { return hasResults; }
            set { hasResults = value; RaisePropertyChanged("HasResults"); }
        }

        private Book selectedBook;
        public Book SelectedBook
        {
            get { return selectedBook; }
            set { selectedBook = value; RaisePropertyChanged("SelectedBook"); }
        }

        private Settings mySettings;
        public Settings MySettings
        {
            get { return mySettings; }
            set { mySettings = value; RaisePropertyChanged("MySettings"); }
        }

        private Settings mySettings_Shallow;
        public Settings MySettings_Shallow
        {
            get { return mySettings_Shallow; }
            set { mySettings_Shallow = value; RaisePropertyChanged("MySettings_Shallow"); }
        }

        private bool displaySearchBox;
        public bool DisplaySearchBox
        {
            get { return displaySearchBox; }
            set
            {
                displaySearchBox = value; RaisePropertyChanged("DisplaySearchBox");
                if (displaySearchBox) IsSearchBoxFocused = true;
            }
        }

        private bool isSearchBoxFocused;
        public bool IsSearchBoxFocused
        {
            get { return isSearchBoxFocused; }
            set { isSearchBoxFocused = value; RaisePropertyChanged("IsSearchBoxFocused"); }
        }

        private string searchText;
        public string SearchText
        {
            get { return searchText; }
            set
            {
                searchText = value; RaisePropertyChanged("SearchText");
                ClearSearchVisibility = IsWatermarkOrBlank() ? Visibility.Hidden : Visibility.Visible;
            }
        }

        private Visibility clearSearchVisibility;
        public Visibility ClearSearchVisibility
        {
            get { return clearSearchVisibility; }
            set { clearSearchVisibility = value; RaisePropertyChanged("ClearSearchVisibility"); }
        }

        public ICommand OpenBookDetailsCommand { get; private set; }
        public ICommand CloseBookDetailsCommand { get; private set; }
        public ICommand SearchBookCommand { get; private set; }
        public ICommand ClearSearchTextCommand { get; private set; }
        public ICommand SearchBoxLostFocusCommand { get; private set; }
        public ICommand OpenStatsCommand { get; private set; }
        public ICommand OpenSettingsCommand { get; private set; }
        public ICommand SaveSettingsCommand { get; private set; }
        public ICommand RestoreSettingsCommand { get; private set; }
        #endregion Properties

        #region Constructors
        public MainViewModel()
        {
            InitializeCommands();

            LoadSettings();
            LoadBookXml();

            // Initialize data/config
            DisplayDetails = false;
        }
        #endregion Constructors

        private void LoadSettings()
        {
            string settingsPath = dbp.AppendPath("Settings.xml");

            // Create settings file (one-time load)
            if (!File.Exists(settingsPath)) SaveSettings(settingsPath, Settings.InitialSettings);

            // Load settings from file
            var settingsFromFile = File.ReadAllText(settingsPath).DeSerializeFromFormattedData<Settings>(eSerializationFormat.Xml);
            Dictionary<string, object> dictSettingsFromFile = new Dictionary<string, object>();
            settingsFromFile.GetType().GetProperties().ForEach(prop =>
                {
                    var propVal = prop.GetValue(settingsFromFile, null);
                    if (!propVal.IsNull()) dictSettingsFromFile.Add(prop.Name, propVal);
                });

            // Get mismatch and save (for new settings introduced)
            var allProperties = typeof(Settings).GetProperties();
            if (dictSettingsFromFile.Count() != allProperties.Count())
            {
                allProperties.ForEach(classProp =>
                {
                    var fileProp = typeof(Settings).GetProperty(classProp.Name);
                    if (fileProp.GetValue(settingsFromFile, null).IsNull())
                        fileProp.SetValue(settingsFromFile, classProp.GetValue(Settings.InitialSettings, null), null);
                });

                SaveSettings(settingsPath, settingsFromFile);
            }

            // Use settings from file
            MySettings = settingsFromFile;
        }

        private static void SaveSettings(string path, Settings settings)
        {
            File.WriteAllText(path, settings.SerializeToFormattedData(eSerializationFormat.Xml));
        }

        private void InitializeCommands()
        {
            // Initialize commands
            OpenBookDetailsCommand = new RelayCommand<Book>((parameter) => { SelectedBook = parameter; DisplayDetails = true; });
            CloseBookDetailsCommand = new RelayCommand<object>((parameter) => { SelectedBook = null; DisplayDetails = false; });
            SearchBookCommand = new RelayCommand<string>((parameter) => { DisplaySearchBox = false; SearchBook(parameter); });
            ClearSearchTextCommand = new RelayCommand<string>((parameter) => { SearchText = String.Empty; SearchBookCommand.Execute(SearchText); });
            SearchBoxLostFocusCommand = new RelayCommand<string>((parameter) => { if (IsWatermarkOrBlank()) DisplaySearchBox = false; IsSearchBoxFocused = false; });
            OpenStatsCommand = new RelayCommand<string>((parameter) => { new StatsWindow(this).ShowDialog(); });
            OpenSettingsCommand = new RelayCommand<string>((parameter) => { new SettingsWindow(this).ShowDialog(); });
            SaveSettingsCommand = new RelayCommand<string>((parameter) => { MySettings = MySettings_Shallow.ShallowCopy(); });
            RestoreSettingsCommand = new RelayCommand<string>((parameter) => { MySettings_Shallow = MySettings.ShallowCopy(); });
        }

        #region Methods
        /// <summary>
        /// http://stackoverflow.com/questions/7119806/c-sharp-reading-data-from-xml
        /// http://www.codeproject.com/Articles/4902/Reading-an-XML-file-using-NET
        /// http://csharp.net-informations.com/xml/how-to-read-xml.htm
        /// http://www.c-sharpcorner.com/UploadFile/167ad2/read-xml-file-using-xml-reader-in-C-Sharp/
        /// http://csharp.net-tutorials.com/xml/reading-xml-with-the-xmlreader-class/
        /// </summary>
        private void LoadBookXml()
        {
            // RKD Trace with milisecs

            string filePath = dbp.AppendPath("Book Collection.xml");

            //var doc = XDocument.Load(filePath);
            ////var nodes = doc.DescendantNodes();
            //var titles = doc.Descendants("Title").Select(xNode => xNode.Value).Distinct();
            //var bindings = doc.Descendants("Binding").Select(xNode => xNode.Value).Distinct();
            ////var authors = doc.Descendants("Author").Select(xNode => xNode.Value).Distinct();
            //var allBooks = new ObservableCollection<Book>();
            //allBooks = titles.Select(bk => new Book { Title = bk }).ToObservableCollection();
            //var str = allBooks.Take(2).ToObservableCollection().SerializeToFormattedData(eSerializationFormat.Xml);
            //var allBooks4 = str.DeSerializeFromFormattedData<ObservableCollection<Book>>(eSerializationFormat.Xml);

            var doc = FormatDB(File.ReadAllText(filePath));
            AllBooks = doc.DeSerializeFromFormattedData<ObservableCollection<Book>>(eSerializationFormat.Xml);
            AllBooks_org = doc.DeSerializeFromFormattedData<ObservableCollection<Book>>(eSerializationFormat.Xml);
            AllFilteredBooks = new ObservableCollection<Book>(AllBooks);

            //if (AllBooks._None())
            //    AllFilteredBooks = AllBooks.AddItem(new Book { Title = "< No books to show >" }).ToObservableCollection();

            ////RKD
            AllBooks.ForEach(bk => bk.PersonalRating = (AllBooks.IndexOf(bk) % 11).ToString());
            var rating = AllBooks.Select(bk => bk.PersonalRating).Distinct();
        }

        private string FormatDB(string data)
        {
            return data.RemoveText("  <title>Items</title>\r\n")
                .Replace("<item>", "<Book>").Replace("</item>", "</Book>")
                .Replace("<channel>", @"<ArrayOfBook xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">")
                .Replace("</channel>", "</ArrayOfBook>");
        }

        private bool IsWatermarkOrBlank()
        {
            return searchText.IsBlank() || searchText == "Search here..";
        }

        private void SearchBook(string searchText)
        {
            if (!IsWatermarkOrBlank() || (IsWatermarkOrBlank() && AllBooks.Count() != AllFilteredBooks.Count()))
                AllFilteredBooks = new ObservableCollection<Book>(
                    IsWatermarkOrBlank() ? AllBooks : AllBooks.Where(bk => bk.Title.Contains(searchText)));
        }
        #endregion Methods
    }
}
